package com.sunreal.paygateway.service.impl;

import java.util.Map;

import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.sunreal.paygateway.common.AssertUtil;
import com.sunreal.paygateway.common.PayConstant;
import com.sunreal.paygateway.dao.model.PayChannel;
import com.sunreal.paygateway.dao.model.PayOrder;
import com.sunreal.paygateway.service.BaseService;
import com.sunreal.paygateway.service.IPayChannel4WxService;
import com.sunreal.paygateway.service.channel.wechat.WxPayProperties;
import com.sunreal.paygateway.service.channel.wechat.WxPayUtil;
import com.sunreal.paygateway.service.channel.wechat.WxResultCheck;
import com.sunreal.paygateway.sys.exception.BusinessException;
import com.sunreal.paygateway.sys.exception.WebErrCode;

/**
 * 功能描述：微信支付接口实现
 *
 * @Author 彭广
 * @Date 2019/4/19
 */
@Service
@Slf4j
public class PayChannel4WXServiceImpl extends BaseService implements IPayChannel4WxService {
    @Resource
    private WxPayProperties wxPayProperties;

    /**
     * 微信支付统一下单
     *
     * @param payOrder 订单信息
     * @return 微信支付页面，二维码
     */
    @Override
    public Map<String, Object> doWxPayReq(PayOrder payOrder) throws BusinessException {
        String logPrefix = "【微信支付统一下单】";
        try {
            String mchId = payOrder.getMchid();
            String channelId = payOrder.getChannelid();
            PayChannel payChannel = super.baseSelectPayChannelByMchIdAndChannelId(mchId, channelId);
            AssertUtil.notBlank(payChannel, "商户不支持该渠道支付方式[" + channelId + "]，联系管理员");
            WxPayConfig wxPayConfig = WxPayUtil.getWxPayConfig(payChannel.getParam(), payOrder.getChannelid(), wxPayProperties.getCertRootPath(), wxPayProperties.getNotifyUrl());
            WxPayService wxPayService = new WxPayServiceImpl();
            wxPayService.setConfig(wxPayConfig);
            WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = buildUnifiedOrderRequest(payOrder, wxPayConfig);
            String payOrderId = payOrder.getPayorderid();
            WxPayUnifiedOrderResult wxPayUnifiedOrderResult;
            try {
                if (wxPayConfig.isUseSandboxEnv()) {
                    String sandbox_signkey = wxPayService.getSandboxSignKey();
                    wxPayConfig.setMchKey(sandbox_signkey);
                    wxPayUnifiedOrderResult = wxPayService.unifiedOrder(wxPayUnifiedOrderRequest);
                } else {
                    wxPayUnifiedOrderResult = wxPayService.unifiedOrder(wxPayUnifiedOrderRequest);
                }
                log.info("微信返回下单结果：{}", wxPayUnifiedOrderResult.toString());
                //检查微信返回结果，如果存在错误则直接抛出WxPayException，不再走后续代码
                Map<String, Object> map = WxResultCheck.checkResult(wxPayUnifiedOrderResult);
                log.info("{} >>> 下单成功{}", logPrefix, wxPayService.getConfig().isUseSandboxEnv());
                //不抛异常说明成功，更新订单状态为支付中
                int result = super.baseUpdateStatus4Ing(payOrderId, PayConstant.PAY_STATUS_PAYING, wxPayUnifiedOrderResult.getPrepayId());
                log.info("更新第三方支付订单号:payOrderId={},prepayId={},result={}", payOrderId, wxPayUnifiedOrderResult.getPrepayId(), result);
                return map;
            } catch (WxPayException e) {
                log.error("下单失败", e);
                //出现业务错误
                log.info("{}下单返回失败", logPrefix);
                log.info("err_code:{}", e.getErrCode());
                log.info("err_code_des:{}", e.getErrCodeDes());
                throw new BusinessException(WebErrCode.PAY_FAILED.getErroCode(), logPrefix + e.getErrCode() + e.getErrCodeDes());
            }
        } catch (Exception e) {
            log.error(WebErrCode.PAY_FAILED.getErroMsg(), e);
            throw new BusinessException(WebErrCode.PAY_FAILED);
        }
    }

    /**
     * 构建微信统一下单请求数据
     *
     * @param payOrder    订单信息
     * @param wxPayConfig 微信配置信息
     * @return
     */
    WxPayUnifiedOrderRequest buildUnifiedOrderRequest(PayOrder payOrder, WxPayConfig wxPayConfig) {
        String tradeType = wxPayConfig.getTradeType();
        String payOrderId = payOrder.getPayorderid();
        Integer totalFee = payOrder.getAmount().intValue();// 支付金额,单位分
        String deviceInfo = payOrder.getDevice();
        String body = payOrder.getBody();
        String detail = null;
        String attach = null;
        String outTradeNo = payOrderId;
        String feeType = "CNY";
        String spBillCreateIP = payOrder.getClientip();
        String timeStart = null;
        String timeExpire = null;
        String goodsTag = null;
        String notifyUrl = wxPayConfig.getNotifyUrl();
        String productId = null;
        if (tradeType.equals(PayConstant.WxConstant.TRADE_TYPE_NATIVE))
            productId = JSON.parseObject(payOrder.getExtra()).getString("productId");
        String limitPay = null;
        String openId = null;
        if (tradeType.equals(PayConstant.WxConstant.TRADE_TYPE_JSPAI))
            openId = JSON.parseObject(payOrder.getExtra()).getString("openId");
        String sceneInfo = null;
        if (tradeType.equals(PayConstant.WxConstant.TRADE_TYPE_MWEB))
            sceneInfo = JSON.parseObject(payOrder.getExtra()).getString("sceneInfo");
        // 微信统一下单请求对象
        WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
        request.setDeviceInfo(deviceInfo);
        request.setBody(body);
        request.setDetail(detail);
        request.setAttach(attach);
        request.setOutTradeNo(outTradeNo);
        request.setFeeType(feeType);
        request.setTotalFee(totalFee);
        request.setSpbillCreateIp(spBillCreateIP);
        request.setTimeStart(timeStart);
        request.setTimeExpire(timeExpire);
        request.setGoodsTag(goodsTag);
        request.setNotifyUrl(notifyUrl);
        request.setTradeType(tradeType);
        request.setProductId(productId);
        request.setLimitPay(limitPay);
        request.setOpenid(openId);
        request.setSceneInfo(sceneInfo);

        return request;
    }
}
